#include <iostream>
#include <memory>
#include <typeinfo>
#include <utility>

using namespace std;

class Foo {
 public:
  Foo(const int& x) : mx(x) {}

 private:
  int mx;
};

// 传统的工厂模板，需要把参数传递给 T 的构造。
// 需要写两套代码， 一个 const 版本和 一个非 const 版本
template <typename T, typename Arg>
shared_ptr<T> factory(Arg& arg /*改成（左值）引用*/) {
  std::cout << "factory(Arg& arg)" << std::endl;
  return shared_ptr<T>(new T(arg));
}

template <typename T, typename Arg>
shared_ptr<T> factory(const Arg& arg) {
  std::cout << "factory(const Arg& arg)" << std::endl;
  return shared_ptr<T>(new T(arg));
}

class CBase {
 public:
  CBase(int&) { cout << "CBase(int&)" << endl; }

  CBase(int&&) { cout << "CBase(int&&)" << endl; }
};

// 使用完美转发，可以实现：
//   1. 调用 wrapper (factory)时传递的是左值，内层函数被调用时得到的就是左值
//   2. 调用 wrapper (factory)时传递的是右值，内层函数被调用时得到的就是右值
// 原因是 C++11的 万能引用 和 引用折叠 功能
// 从 C++11
// 开始，规定了一种特殊的形式下，函数形参既可以匹配左值，也可以匹配右值。
// 这种情况必须是模板的形式，并且以&& 作为形参数。
// 它被称为“万能引用”（英文为 universal reference 或 forwarding reference）。

// 引用折叠:
//  C++11 之后，引用的引用在特定情况下允许存在，
// 他们会在编译时，被自动化简为左值引用或者右值引用，化简的过程称为 "引用折叠"。
// 化简的规则如下：
// T& &   => T&
// T&& &  => T&
// T& &&  => T&
// T&& && => T&&
template <typename T, typename Arg>
shared_ptr<T> facotry(Arg&& arg) {
  std::cout << "factory(Arg&& arg), type Arg: " << typeid(arg).name()
            << std::endl;
  return shared_ptr<T>(new T(std::forward<Arg>(arg)));
}

int main() {
  int value = 5;
  std::cout << typeid(int).name() << std::endl;

  factory<Foo, int>(value);
  factory<Foo, int>(5);  // 传递右值
  std::cout << "------------111--------------\n";
  auto p1 = facotry<CBase>(5);  // 传递右值，内部调用的也是右值引用
  std::cout << "------------2222--------------\n";
  auto p2 = facotry<CBase>(value);  // 传递左值，内部调用的左值引用
  std::cout << "------------3333--------------\n";
  auto p3 = facotry<CBase>(std::move(value));  //
}